package com.sghd.fight.module.game.service.skill.effect;

import com.sghd.fight.module.game.config.BuffConfig;
import com.sghd.fight.module.game.config.ElementConfig;
import com.sghd.fight.module.game.config.ElementPk;
import com.sghd.fight.module.game.config.SkillConfig;
import com.sghd.fight.module.game.core.ChessBoard;
import com.sghd.fight.module.game.core.model.Buff;
import com.sghd.fight.module.game.core.model.EliminateResult;
import com.sghd.fight.module.game.core.model.Unit;
import com.sghd.fight.module.game.service.room.IRoom;
import com.sghd.fight.module.game.service.room.Player;
import com.sghd.fight.module.game.service.skill.Context;
import com.sghd.pojo.fight.game.ChessType;
import com.sghd.pojo.fight.game.SkillReport;
import com.sghd.pojo.fight.game.TargetReport;
import com.sghd.pojo.fight.game.UnitValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 技能效果
 * @author frank
 * @date 2016年11月23日 下午9:06:33
 */
public interface Effect {
    public Logger logger = LoggerFactory.getLogger(Effect.class);

    /** 自己*/
    public static final String TARGET_SEL = "self";
    /** 敌军*/
    public static final String TARGET_ENEMY = "enemy";
    /** 自己和敌军*/
    public static final String TARGET_ALL = "all";

    /** 所有者 */
    String OWNER = "owner";
    /** 来源*/
    String SOURCE = "source";
    /** 目标 */
    String TARGET = "target";
    /** 值 */
    String VALUE = "value";
    /** buffID*/
    String BUFF_ID = "buffId";
    /**是否是自己*/
    String IS_SELF = "isSelf";
    /** 魔法值类型*/
    String MAGIC_TYPE = "magicType";
    /** 魔法值类型*/
    String MAGIC_VALUE = "magicValue";
    /** 白色棋子数量*/
    String LIGHTING = "lighting";
    /** 恢复*/
    String RECOVER = "recover";
    /** 攻击力*/
    String ATTACK = "attack";
    /** 魔法盾少于一定值不消耗回合*/
    String MSHIE_LIMIT = "mshieLimit";
    /** 风行术增加回合机会*/
    String POPULARART_ADD = "popularAdd";
    /** 消耗*/
    String CONSUME = "consume";
    /** 数量*/
    String COUNT = "count";
    /** 最大*/
    String MAX = "max";
    /** 片断*/
    String SEGMENT = "segment";
    /** 额外控制*/
    String EXTRTIME = "extrTime";
    /** 额外伤害*/
    String EXTRVALUE = "extrValue";
    /** 额外等级*/
    String LEVEL = "level";

    void execute(Context context, IRoom room, Unit owner, Unit target, Map<String, Object> ctx, SkillReport skillReport, TargetReport targetReport, SkillConfig config);

    /**
     * 计算血量
     * @param target
     * @param val
     * @return
     */
    default int fixHp(Unit owner, Unit target, int val, IRoom room, SkillConfig skillConfig) {
        if (val == 0) {
            return val;
        }
        /** 五行增减*/
        val = elementFix(owner, target, room, skillConfig, val);
        /** 检查普通盾*/
        val = checkShield(target, val);
        /** 魔法盾*/
        val = checkMagicShield(target, val);
        logger.debug("最终造成的伤害：{}", val);
        return val;
    }

    default int elementFix(Unit owner, Unit target, IRoom room, SkillConfig skillConfig, int val) {
        //加伤
        if (owner instanceof Player && skillConfig.getType() != null) {
            Map<ChessType, Integer> attr2Level = ((Player) owner).getElement2Level();
            int level = attr2Level.get(skillConfig.getType());
            for (; level > 0; level--) {
                ElementPk pk = ElementPk.valueOf(skillConfig.getType(), level);
                ElementConfig attrConfig = room.getConfigService().getAttr(pk);
                if (logger.isDebugEnabled()) {
                    logger.debug("玩家[{}]五行额外增加伤害：{}", owner.getId(), attrConfig.getAttr(room.getType()).getInHarm());
                }
                val += attrConfig.getAttr(room.getType()).getInHarm();//五行额外加攻
            }
        }
        //减伤
        if (target instanceof Player && skillConfig.getType() != null) {
            Map<ChessType, Integer> attr2Level = ((Player) target).getElement2Level();
            int level = attr2Level.get(skillConfig.getType());
            for (; level > 0; level--) {
                ElementPk pk = ElementPk.valueOf(skillConfig.getType(), level);
                ElementConfig attrConfig = room.getConfigService().getAttr(pk);
                if (logger.isDebugEnabled()) {
                    logger.debug("玩家[{}]五行额外减少伤害：{}", target.getId(), attrConfig.getAttr(room.getType()).getDeHarm());
                }
                val -= attrConfig.getAttr(room.getType()).getDeHarm();//五行额外减攻
            }
        }
        return val < 0 ? 0 : val;
    }

    /**
     * 魔法盾，抵扣
     * @param target
     * @param val
     * @return
     */
    default int checkMagicShield(Unit target, int val) {
        logger.debug("攻击造成伤害：{}", val);
        Set<Integer> targetRemove = new HashSet<>();
        for (Buff buff : target.getBuffs().values()) {
            if (buff.getType() == UnitValue.MAGIC_SHIELD) {//敌方魔法盾
                ChessType type = ChessType.valueOf(buff.getCtx().get(Effect.MAGIC_TYPE).toString());
                int magic = target.getMagic(type);
                if (val >= magic) {
                    val = val - magic;
                } else {
                    magic = val;
                    val = 0;
                }
                logger.debug("当前魔法值 ：{}", target.getMagic().getMagic(type));
                logger.debug("扣除的魔法值：{}", magic);
                target.getMagic().update(type, -magic);//魔法值抵扣血量
                if (buff.isRemove()) {
                    targetRemove.add(buff.getId());
                    logger.debug("[{}]魔法盾，被打破！", type);
                }
                //TODO 检查是否移除 魔法盾
            }
        }
        target.removeBuff(targetRemove);//移除buff(雷魔法盾被打破)
        return val;
    }

    /**
     * 检查盾
     * */
    default int checkShield(Unit target, int val) {
        //敌方有能量盾
        if (target.hasBuf(UnitValue.ENERGY_SHIELD)) {
            logger.debug("敌方有能量盾：{}", val);
            val = target.getValue(UnitValue.ENERGY_SHIELD);
        }
        if (target.hasBuf(UnitValue.STONESKIN)) {
            logger.debug("敌方有石质皮肤：{}", val);
            val = val - target.getValue(UnitValue.STONESKIN);
            if (val < 0) {
                val = 0;
            }
        }
        if (target.hasBuf(UnitValue.ARMOUR)) {
            logger.debug("敌方有强化铠甲：{}", val);
            val = 0;
        }
        if (target.hasBuf(UnitValue.THUNDER_SHIELD)) {
            logger.debug("敌方有雷盾：{}", val);
            val = 0;
        }
        return val;
    }

    default Buff getBuff(SkillConfig skillConfig, BuffConfig buffConfig, Map<String, Object> ctx, Unit owner, Unit target) {
        UnitValue unitValue = buffConfig.getValue();//buff对应的游戏单位属性
        long start = System.currentTimeMillis();
        ctx.putAll(buffConfig.getContext());
        //buff数值
        int value = buffConfig.calc(ctx);
        //buff持续时间/冷确
        int time = buffConfig.calcTime(ctx);
        int level = owner.getSkillLevel(skillConfig.getId());
        return Buff.valueOf(buffConfig.getId(), skillConfig.getId(), unitValue, value, time, start, buffConfig.getCoolVal(), ctx, level);
    }

    default double getBet(Unit owner, Unit target) {
        double magicShield = owner.getValue(UnitValue.MAGIC_SHIELD) / 100.0;
        if (magicShield != UnitValue.MAGIC_SHIELD.getValue() / 100.0) {
            return magicShield;//魔法盾
        }
        double timeStatic = target.getValue(UnitValue.TIME_STATIC) / 100.0;
        if (timeStatic != UnitValue.TIME_STATIC.getValue() / 100.0) {
            return timeStatic;//时间静止
        }
        double doubleAttack = owner.getValue(UnitValue.DOUBLE_ATTACK) / 100.0;
        if (doubleAttack != UnitValue.DOUBLE_ATTACK.getValue() / 100.0) {
            return doubleAttack;//双重攻击
        }
        return 1.0;
    }

    /**
     * 执行技能后自消
     * @param room
     * @param owner
     * @param skillReport
     * @param chessBoard
     */
    default void autoElimi(IRoom room, Unit owner, SkillReport skillReport, ChessBoard chessBoard) {
        //拷贝一个棋盘，检测自动消除后是不是死盘（此时房间内棋盘并未真正执行）
        EliminateResult temp = new EliminateResult();
        ChessBoard copyOf = chessBoard.copy();
        while (copyOf.autoElim1(temp)) {
            copyOf.fill();
        }
        //增加回合
        room.checkRound(temp, owner);
        List<List<Integer>> tempCanElim = copyOf.canElim(false);
        if (tempCanElim.isEmpty()) {
            logger.debug("棋盘变更后Rset为[{}]", true);
            skillReport.setReset(true);
        }
        //如果有自动消除，则在当前技能消息反回客户端以后再真正执行自动消除逻辑
        room.submit(now -> {
            logger.debug("棋盘变更后，检查并执行自动消除逻辑！");
            //自动消除
            EliminateResult result = new EliminateResult();
            while (chessBoard.autoElim1(result)) {
                chessBoard.fill();
            }
            List<List<Integer>> canElim = chessBoard.canElim(false);
            if (canElim.isEmpty()) {
                logger.debug("棋盘变更后，无法再消除！");
                chessBoard.reset();//重置棋盘
            }
            if (owner instanceof Player) {
                //收集元素
                room.collect(result, owner);
            }
            //执行白色技能
            room.checkSkill(result);
        });
    }

    /**
     * 五行额外提供的hp恢复
     * @param unit
     * @return
     */
    default int getAddedHp(Unit unit, IRoom room, ChessType type) {
        if (unit instanceof Player) {
            Map<ChessType, Integer> attr2Level = ((Player) unit).getElement2Level();
            int total = 0;
            int level = attr2Level.get(type);
            for (; level > 0; level--) {
                ElementPk pk = ElementPk.valueOf(type, level);
                ElementConfig attrConfig = room.getConfigService().getAttr(pk);
                //五行额外恢复量
                total += attrConfig.getAttr(room.getType()).getExtraRecover();
            }
            return total;
        }
        return 0;
    }

    EffectType getType();
}
